package com.xohm.platform.api;

import com.sun.jna.*;
import com.xohm.base.Properties;
import com.xohm.base.logging.XohmLogger;
import com.xohm.platform.ProcDylib;

import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.lang.management.ManagementFactory;
import java.lang.reflect.Method;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.net.UnknownHostException;
import java.util.Enumeration;
import java.util.Vector;
import java.util.regex.MatchResult;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.xml.sax.InputSource;

/**
 * Xohm Connection Manager
 *
 * Licensed Material - Property of Sprint Nextel
 * Restricted Materials of Sprint Nextel
 * (C) Copyright Sprint Nextel Corp. 2008 - All Rights Reserved.
 *
 * This class contains the methods for checking an existing CM is
 * running and also for the location of the WiMax drivers on the
 * Macintosh system.
 *
 * @author Robin Katzer
 */

public class OSAPIMac extends OSAPIPidLookup implements OSAPIInterface
{
	private ProcDylib procDylib = null;
	private Vector<DriverInformation> drivers = null;
	
	public OSAPIMac()
	{
		try
		{
			procDylib = (ProcDylib)Native.loadLibrary("proc", ProcDylib.class);
		}
		catch (Exception e)
		{
			XohmLogger.fatalPrintln(e.toString(), null, null);
			e.printStackTrace();
		}
	}
	
	/**
	 * This method attempt to retrieve this applications process id.
	 * 
	 * @param pidToFind int process id to find
	 * @return boolean
	 */
	public boolean isProcessRunning(int pidToFind)
	{
		boolean exists = false;
		
		try
		{
			int results = procDylib.GetProcessByPID(pidToFind);
			if (results > 1) exists = true;
		}
		catch (Exception e)
		{
			XohmLogger.fatalPrintln("Exception: "+e.toString(), null, null);
		}

		return exists;
	}
	
	/**
	 * This method attempt to retrieve this applications process id.
	 * 
	 * @return int process id
	 */
	public int getProcessId()
	{
		int pid = -1;
		
		// Works for windows & Mac 10.4
		String result = ManagementFactory.getRuntimeMXBean().getName();
		if (result != null)
		{
			int end = result.indexOf("@");
			if (end > 0)
			{
				result = result.substring(0, end);
				if (result != null && !result.trim().equals(""))
					pid = Integer.valueOf(result).intValue();
			}
		}
		
		return pid;
	}
	
	/**
	 * Get the driver information for all WiMax installed drivers on this machine
	 * and return it to the receiver.
	 * 
	 * @return java.util.Vector<com.xohm.platform.api.DriverInformation>  Each Vector
	 *             entry is a driver, the keys within the HashMap are "Path" and
	 *             "Extension" to describe the driver name and location.
	 */
	public Vector<DriverInformation> getAvailableDriverInformation()
	{
		if (drivers == null)
		{
			// Read driver information "wimax_driver.plist" file
			FileInputStream fileInStream = null;
			try
			{
				java.io.File file = new java.io.File("/Library/Preferences/wimax_drivers.plist");
				if (file.canRead())
				{
					fileInStream = new FileInputStream(file);
					if (fileInStream != null)
					{
						InputSource is = new InputSource(fileInStream);
			
						// Parse it using a SAX parser to get the driver information
						drivers = DriverXMLParserHandler.parsePropertiesXML(is);
						
						fileInStream.close();
					}
				}
			}
			catch (Exception e)
			{
				try
				{
					if (fileInStream != null) fileInStream.close();
				} catch (Exception e2) {}
			}
			
			if (drivers == null)
				drivers = new Vector<DriverInformation>();
		}
		
		return drivers;
	}
	
	/**
	 * Open the URL specified.<br><br>
	 * 
	 * @param url java.lang.String
	 */
	public void openUrl(String url)
	{
		try 
		{ 
			Class<?> fileMgr = Class.forName("com.apple.eio.FileManager");
         Method openURL = fileMgr.getDeclaredMethod("openURL", new Class[] {String.class});
         openURL.invoke(null, new Object[] {url});
		} 
		catch (Exception ex)
		{
			XohmLogger.warningPrintln("Could not open the url: " + url + " - Reason:" + ex.getMessage(), null, null);
		}
	}
	
	/**
	 * Returns the matched line containing default gateway and interface.
	 * 
	 * @return MatchResult - matched line
	 */
	private MatchResult getMatchedLine() {
		MatchResult result = null;
        String _255 = "(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)";
        String exIP = "(?:" + _255 + "\\.){3}" + _255;
 
        // Regexp to find the good line
        Pattern pat = Pattern.compile("^\\s*(?:default\\s*){1}("+exIP+").*");
        Process proc;
        try {
            // netstat command
            proc = Runtime.getRuntime().exec("netstat -rn");
       
            InputStream inputstream = proc.getInputStream();
            InputStreamReader inputstreamreader = new InputStreamReader(inputstream);
            BufferedReader bufferedreader = new BufferedReader(inputstreamreader);
    
            // Parsing the result
            String line;
            while ((line = bufferedreader.readLine()) != null) {
                Matcher m = pat.matcher(line);
                if(m.matches()){                	
                	result = m.toMatchResult();
                	break;
                }
            }
        } catch (IOException ex) {
        	XohmLogger.warningPrintln("Exception occured while retrieving the Gateway IP", null, null);
        }
        
        return result;
	}
	
	/**
	 * This method returns the default gateway ip address.
	 */
	public String getGatewayIP() {
		String gatewayIP = "";
		MatchResult result = getMatchedLine();
        if(result != null && result.groupCount() > 0)
        	gatewayIP = result.group(1);
        
        return gatewayIP;
	}
	
	/**
	 * This method returns the currently active interface.
	 */
	public String getActiveInterface() throws UnknownHostException {
		String activeInterface = "";
		String localIP = "";
		MatchResult result = getMatchedLine();
		if(result != null) {
			String matchedLine = result.group().trim();	
			activeInterface = matchedLine.substring(matchedLine.lastIndexOf(" ")+1);

			try {
				Enumeration<NetworkInterface> interfaces = NetworkInterface.getNetworkInterfaces(); 
				while(interfaces.hasMoreElements()) {
					NetworkInterface ni = (NetworkInterface) interfaces.nextElement();
		            Enumeration<InetAddress> e2 = ni.getInetAddresses();
		            while (e2.hasMoreElements()){
		            	InetAddress inAddr = (InetAddress) e2.nextElement();		            	
		                if(activeInterface.equals(ni.getDisplayName())) {
		            	    localIP = (inAddr).toString().split("/")[1];	            	   
		            	    break;
		                }	               
		            }
		        }
			}catch (Exception ex) {
		    	ex.printStackTrace();
		    }
		}

        if("".equals(activeInterface) || "".equals(localIP)) {
        	throw new UnknownHostException("Active Interface not found.");
        }
                	        
        return activeInterface + "/" + localIP;
	}
	
	/**
	 * This method performs the ping operation for the specified target 
	 * using the specified options.
	 * 
	 * @param target String - ping target
	 * @param count int - number of packets
	 * @param packetSize int - size of ping packet
	 * @param timeout int - timeout period
	 */
	public Process ping(String target, int count, int packetSize, int timeout) {
		String cmd = "ping -c " + count + " -s " + (packetSize - 8) +
		" -t " + timeout + " " + target;
		
		Process pingProc = null;
		try {			
			pingProc = Runtime.getRuntime().exec(cmd);
		}catch(Exception ex) {
			XohmLogger.warningPrintln("Exception occured when pinging the target " + target, null, null);
		}	

		return pingProc;
	}
	
	/**
	 * This method returns the mac address for the specified interface name.
	 * 
	 * @param interfaceName String - name of interface.
	 */
	public String getMacAddress(String interfaceName) {
		String macAddress = "";
		try {
			Process pingProc = Runtime.getRuntime().exec("ifconfig " + interfaceName);
			InputStream stream = pingProc.getInputStream();
			BufferedReader in = new BufferedReader(new InputStreamReader(stream, "UTF-8"));			
	    	String line;	    	
	    	while ((line = in.readLine()) != null) {	    		
	    		if(line.contains("ether".subSequence(0, 5))) {    				
	    			String[] splitArr = line.split(" ");
	    			macAddress = splitArr[splitArr.length -1].trim();		    		
		    		break;
	    		}
		    }
		}catch(Exception ex) {
			XohmLogger.warningPrintln("Exception occured in retrieveing the MAC address for interface " + interfaceName, null, null);
		}
		return macAddress;
	}
	
	/**
	 * This method add a listener for the device insert notification.
	 * 
	 * @param callbackObj Object - callback object
	 * @param callbackMethodName String - callback method name
	 */
	public void addDeviceInsertListener(Object callbackObj, String callbackMethodName) {
		OSAPICommonHelper helper = new OSAPICommonHelper();
		helper.addDeviceInsertListener(callbackObj, callbackMethodName);
	}
	
	/**
	 * This method updates the maximum size used for native string datatypes.
	 * It should be called before doing any native api calls.
	 */
	public void setMaxSizeForNativeTypes() {
		Properties.MAX_SIZE_OF_NSP_NAME = 64;
		Properties.MAX_SIZE_OF_STRING_BUFFER = 128;
	}
}
